# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: site-packages\PyInstaller\building\toc_conversion.py
import os, zipfile, pkg_resources
from ..depend.utils import get_path_to_egg
from .datastruct import TOC, Tree
from .. import log as logging

logger = logging.getLogger(__name__)
from ..utils.hooks import PY_IGNORE_EXTENSIONS, PY_EXECUTABLE_SUFFIXES

PY_IGNORE_EXTENSIONS = set(
    ("*" + s for s in PY_IGNORE_EXTENSIONS | PY_EXECUTABLE_SUFFIXES)
)
PY_IGNORE_EXTENSIONS = PY_IGNORE_EXTENSIONS | set(["EGG-INFO"])


class DependencyProcessor(object):
    """
    Class to convert final module dependency graph into TOC data structures.
    TOC data structures are suitable for creating the final executable.
    """

    def __init__(self, graph, additional_files):
        self._binaries = set()
        self._datas = set()
        self._distributions = set()
        self._DependencyProcessor__seen_distribution_paths = set()
        for node in graph.flatten(start=graph._top_script_node):
            name = node.identifier
            if name in additional_files:
                self._binaries.update(additional_files.binaries(name))
                self._datas.update(additional_files.datas(name))
            self._distributions.update(self._get_distribution_for_node(node))

    def _get_distribution_for_node(self, node):
        """Get the distribution a module belongs to.
        
        Bug: This currently only handles packages in eggs.
        """
        modpath = node.filename
        if not modpath:
            return []
        else:
            distpath = get_path_to_egg(modpath)
            if (
                not distpath
                or distpath in self._DependencyProcessor__seen_distribution_paths
            ):
                return []
            self._DependencyProcessor__seen_distribution_paths.add(distpath)
            dists = list(pkg_resources.find_distributions(distpath))
            if not len(dists) == 1:
                raise AssertionError
            dist = dists[0]
            dist._pyinstaller_info = info = {
                "zipped": zipfile.is_zipfile(dist.location),
                "egg": True,
                "zip-safe": dist.has_metadata("zip-safe"),
            }
            return dists

    def make_binaries_toc(self):
        return [(x, y, "BINARY") for x, y in self._binaries]

    def make_datas_toc(self):
        toc = TOC(((x, y, "DATA") for x, y in self._datas))
        for dist in self._distributions:
            if dist._pyinstaller_info["egg"]:
                if not dist._pyinstaller_info["zipped"]:
                    if not dist._pyinstaller_info["zip-safe"]:
                        toplevel = dist.get_metadata("top_level.txt").strip()
                        basedir = dist.location
                        if toplevel:
                            os.path.join(basedir, toplevel)
                        tree = Tree(dist.location, excludes=PY_IGNORE_EXTENSIONS)
                        toc.extend(tree)

        return toc

    def make_zipfiles_toc(self):
        toc = []
        for dist in self._distributions:
            if dist._pyinstaller_info["zipped"]:
                if not dist._pyinstaller_info["egg"]:
                    toc.append(
                        (
                            "eggs/" + os.path.basename(dist.location),
                            dist.location,
                            "ZIPFILE",
                        )
                    )

        return toc

    @staticmethod
    def __collect_data_files_from_zip(zipfilename):
        from ..config import CONF

        workpath = os.path.join(CONF["workpath"], os.path.basename(zipfilename))
        try:
            os.makedirs(workpath)
        except OSError as e:
            import errno

            if e.errno != errno.EEXIST:
                raise

        with zipfile.ZipFile(zipfilename) as (zfh):
            zfh.extractall(workpath)
        return Tree(workpath, excludes=PY_IGNORE_EXTENSIONS)

    def make_zipped_data_toc(self):
        toc = TOC()
        logger.debug("Looking for egg data files...")
        for dist in self._distributions:
            toplevel = (
                dist._pyinstaller_info["egg"]
                and dist.get_metadata("top_level.txt").strip()
            )
            if dist._pyinstaller_info["zipped"]:
                tree = self._DependencyProcessor__collect_data_files_from_zip(
                    dist.location
                )
                toc.extend(tree)
            elif dist._pyinstaller_info["zip-safe"]:
                basedir = dist.location
                if toplevel:
                    os.path.join(basedir, toplevel)
                tree = Tree(dist.location, excludes=PY_IGNORE_EXTENSIONS)
                toc.extend(tree)
                continue

        return toc
